package org.liaohailong.library.widget

import android.content.Context
import android.graphics.Matrix
import android.graphics.SurfaceTexture
import android.media.MediaPlayer
import android.util.AttributeSet
import android.view.Surface
import android.view.TextureView

/**
 * Author: liaohailong
 * Date: 2019/3/16
 * Time: 22:19
 * Description:
 **/
class TextureVideoView(context: Context, attributeSet: AttributeSet?, defStyle: Int) :
        TextureView(context, attributeSet, defStyle),
        MediaPlayer.OnPreparedListener,
        MediaPlayer.OnCompletionListener,
        MediaPlayer.OnErrorListener,
        MediaPlayer.OnVideoSizeChangedListener {
    constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
    constructor(context: Context) : this(context, null)

    companion object {
        const val SCREEN_CENTER_CROP = 0
        const val SCREEN_CENTER_INSIDE = 1
        const val SCREEN_16_9 = 2
        const val SCREEN_4_3 = 3
        const val SCREEN_FIT_XY = 4
    }

    private var mode = SCREEN_CENTER_INSIDE
    private var videoWidth = 0
    private var videoHeight = 0

    private val playObserver: MutableSet<OnTextureVideoViewCallback> = mutableSetOf()
    private var mediaPlayer: MediaPlayer? = null
    private var isMediaPlayerSetSurface = false
    private var isFirstMediaPrepared = false
    private var surface: Surface? = null

    private var seekTime = 0

    init {
        surfaceTextureListener = object : SurfaceTextureListener {
            override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
                this@TextureVideoView.surface = Surface(surface)
                isMediaPlayerSetSurface = false
                setMediaPlayerWithSurface()
            }

            override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
                this@TextureVideoView.surface = Surface(surface)
                isMediaPlayerSetSurface = false
            }

            override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {

            }

            override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
                this@TextureVideoView.surface?.release()
                surface?.release()
                this@TextureVideoView.surface = null
                mediaPlayer?.setSurface(null)
                isMediaPlayerSetSurface = false
                return true
            }
        }
    }

    fun addPlayObserver(callback: OnTextureVideoViewCallback) {
        playObserver.add(callback)
    }

    fun removePlayObserver(callback: OnTextureVideoViewCallback) {
        playObserver.remove(callback)
    }

    fun seekForStart(seek: Int) {
        seekTime = seek
    }

    /**
     * 设置视频播放模式
     * {@link #SCREEN_CENTER_CROP} 最大比例展示
     * {@link #SCREEN_CENTER_INSIDE} 最小比例展示
     * {@link #SCREEN_16_9} 16:9展示
     * {@link #SCREEN_4_3}  4:3展示
     * {@link #SCREEN_FIT_XY} 全屏展示（比例失调）
     */
    fun setScreenMode(screenMode: Int) {
        mode = screenMode
    }

    fun play(url: String, cache: Boolean) {
        if (mediaPlayer == null) {
            mediaPlayer = MediaPlayer()
            mediaPlayer!!.setOnPreparedListener(this@TextureVideoView)
            mediaPlayer!!.setOnCompletionListener(this@TextureVideoView)
            mediaPlayer!!.setOnErrorListener(this@TextureVideoView)
            mediaPlayer!!.setOnVideoSizeChangedListener(this@TextureVideoView)
        }
        mediaPlayer?.apply {
            if (isPlaying) stop()
            reset()
//            val uri = if (cache) {
//                MainApplication.INSTANCE.getProxy().getProxyUrl(url)
//            } else url
            setDataSource(url)
            prepareAsync()
        }
    }

    fun getCurrentPosition(): Long {
        return if (mediaPlayer == null) 0 else mediaPlayer!!.currentPosition.toLong()
    }

    fun setMute(mute: Boolean) {
        if (mute) {
            mediaPlayer?.setVolume(0F, 0F)
        } else {
            mediaPlayer?.setVolume(1F, 1F)
        }
    }

    private fun setMediaPlayerWithSurface() {
        if (!isFirstMediaPrepared) return
        if (mediaPlayer == null) return
        if (surface == null) return
        if (isMediaPlayerSetSurface) return
        mediaPlayer!!.setSurface(surface!!)
        isMediaPlayerSetSurface = true
    }

    private fun updateTextureViewSize(mode: Int) {
        if (width <= 0 || height <= 0 || videoWidth <= 0 || videoHeight <= 0) return

        val matrix = Matrix()
        val centerX = width / 2f
        val centerY = height / 2f
        val scaleX = width / videoWidth.toFloat()
        val scaleY = height / videoHeight.toFloat()

        when (mode) {
            SCREEN_CENTER_CROP -> {
                //默认为FIT_XY，先还原
                matrix.preScale(videoWidth / width.toFloat(), videoHeight / height.toFloat(), centerX, centerY)
                val scale = Math.max(scaleX, scaleY)
                matrix.postScale(scale, scale, centerX, centerY)
            }
            SCREEN_CENTER_INSIDE -> {
                //默认为FIT_XY，先还原
                matrix.preScale(videoWidth / width.toFloat(), videoHeight / height.toFloat(), centerX, centerY)
                //把宽度尽可能缩进View区域
                if (scaleX < scaleY) {
                    matrix.postScale(scaleX, scaleX, centerX, centerY)
                }
                //把高度尽可能缩进View区域
                else {
                    matrix.postScale(scaleY, scaleY, centerX, centerY)
                }
            }
            SCREEN_16_9 -> {
                //默认为FIT_XY，先还原
                matrix.preScale(videoWidth / width.toFloat(), videoHeight / height.toFloat(), centerX, centerY)
                //把宽度尽可能缩进View区域
                if (scaleX < scaleY) {
                    matrix.postScale(scaleX, scaleX * 16f / 9f, centerX, centerY)
                }
                //把高度尽可能缩进View区域
                else {
                    matrix.postScale(scaleY * 9f / 16f, scaleY, centerX, centerY)
                }
            }
            SCREEN_4_3 -> {
                //默认为FIT_XY，先还原
                matrix.preScale(videoWidth / width.toFloat(), videoHeight / height.toFloat(), centerX, centerY)
                //把宽度尽可能缩进View区域
                if (scaleX < scaleY) {
                    matrix.postScale(scaleX, scaleX * 4f / 3f, centerX, centerY)
                }
                //把高度尽可能缩进View区域
                else {
                    matrix.postScale(scaleY * 3f / 4f, scaleY, centerX, centerY)
                }
            }
            SCREEN_FIT_XY -> {
                //do nothing...
            }
        }

        setTransform(matrix)
        postInvalidate()
    }

    fun pause() {
        mediaPlayer?.apply {
            if (isPlaying) pause()
            seekTime = currentPosition
        }
    }

    fun resume() {
        mediaPlayer?.apply {
            if (seekTime > 0) {
                seekTo(seekTime)
                seekTime = 0
            }
            start()
        }
    }

    fun release() {
        mediaPlayer?.apply {
            if (isPlaying) stop()
            release()
            mediaPlayer = null
        }
    }

    override fun onPrepared(mp: MediaPlayer?) {
        isFirstMediaPrepared = true
        setMediaPlayerWithSurface()
        for (observer in playObserver) observer.onPrepared()
        if (seekTime > 0L) {
            mp?.seekTo(seekTime)
            seekTime = 0
        }
        mp?.start()
    }

    override fun onVideoSizeChanged(mp: MediaPlayer?, width: Int, height: Int) {
        videoWidth = width
        videoHeight = height
        updateTextureViewSize(mode)
    }

    override fun onCompletion(mp: MediaPlayer?) {
        for (observer in playObserver) observer.onAutoComplete()
    }

    override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
        for (observer in playObserver) observer.onError(what, extra)
        return true
    }

    interface OnTextureVideoViewCallback {
        fun onPrepared()
        fun onAutoComplete()
        fun onError(what: Int, extra: Int)
    }
}